<?php
/**
 * MVC Component - Native Language Support
 * Used to load the language files and provide translations of strings according to the current active language
 *
 * @author Wavetrex (wavetrex@gmail.com)
 * @package CargoClaims
 * @version 1.0.dev
 */
class MVC_NLS
{
	/**
	 * The current loaded language configuration
	 * @var array
	 */
	public static $config = array();

	/**
	 * The language strings, grouped - This is loaded from the language files after self::load_Groups()
	 * @var array
	 */
	public static $groups = array();

	/**
	 * Sets up the NLS by specifying which language is currently to be displayed in the system (key "language:" in the settings.yaml)
	 * @param string $current_language
	 */
	public static function set_Language($language)
	{
//		dump($language);
		// search the "languages:" key in settings to discover the proper location for the $language
		foreach(MVC_Core::$settings['languages'] as $lang) {
			if($lang[0] == $language)
				$lang_iso2 = $lang[1];
		}

		// now, load the $config for the discovered language
		$language_location = ROOT. DS. 'app'. DS. 'nls'. DS. $lang_iso2;
		if(MVC_Core::real_path($language_location. DS. "config.php"))
			include_once $language_location. DS. "config.php";
		else
			throw new MVC_Exception("Unable to locate language configuration file.");
		if(self::$config['name'] != $language)
			throw new MVC_Exception("Misconfiguration in the language settings, please check.");

		self::$config['location'] = $language_location;
	}

	/**
	 * Load langauge files under current language and in the specified groups
	 *
	 * @param string|array $groups
	 */
	public static function load_Groups($groups)
	{
		if(is_string($groups))
			$groups = explode(',', $groups);

		if(empty(self::$config))
			throw new MVC_Exception("Current language not yet set, unable to load language files.");

		// test if the specified groups exist in the $config
		foreach($groups as $group) {
			$group = trim($group);

			if(in_array($group, self::$config['groups'])) { // ok, the language should support this group
				$filename = self::$config['location']. DS. $group. '.yaml';
				if(file_exists($filename))
					self::$groups[$group] = MVC_Core::$spyc-> loadFile($filename);
			}

			if(!isset(self::$groups[$group]) || empty(self::$groups[$group])) {
				// failed to load that specific group in a language, try the default one
				$default_language = MVC_Core::$settings['core']['default_language'];
				if($default_language == self::$config['name']) // current language is the default, and the group wasn't found, abort
					continue;

				// find location for default language
				foreach(MVC_Core::$settings['languages'] as $lang) {
					if($lang[0] == $default_language)
						$lang_iso2 = $lang[1];
				}
				$filename = ROOT. DS. 'app'. DS. 'nls'. DS. $lang_iso2. DS. $group. '.yaml';
				if(file_exists($filename))
					self::$groups[$group] = MVC_Core::$spyc-> loadFile($filename);
				// note that at this point if the loader still failed, there's nothing to be done, simply the group doesn't exist in either the specified language or the default one
			}
		}
	}

	/**
	 * Returns or searches for an object inside the language groups array using a dot.syntax to locate the string
	 * Uses two methods of search - Precise location in the language groups, or Searching anywhere in the groups
	 *
	 * @param string $id
	 * @param bool $precise
	 */
	public static function get_Object($id = false, $precise = true)
	{
		if(!$id)
			// locate all directly
			return self::$groups;

		if($precise)
			// first method, when specifying the object location directly
			return self::locate_Object(self::$groups, $id);
		else
			// second variant, go recursively in the entire $groups array to locate the first key named $id
			return self::search_Object(self::$groups, $id);
	}

	/**
	 * Locates an object using a dot.syntax (the object must exist in the precise location $groups specified by $id)
	 *
	 * @param mixed $where Where to start locating?
	 * @param string $id What to locate
	 */
	private static function locate_Object(&$where, $id)
	{
		$m = explode('.', $id); // exploded dot.syntax id
		foreach($m as $segment) {
			if(is_array($where)) {
				if(isset($where[$segment]))
					$where = &$where[$segment];
				else
					return null;
			} else
				return null; // we still have segments to search, but data is something else, not object, not array - does not contain keys (or member names)
		}
		return $where; // all segments processed, the searched data was found.
	}

	/**
	 * Locates an object anywhere in the $groups, by searching the sequences inside the $id
	 *
	 * @param mixed $where Where to start locating?
	 * @param string $id What to locate
	 */
	private static function search_Object(&$where, $id)
	{
		if(is_array($where)) {

			$locate_res = self::locate_Object($where, $id);
			if(!is_null($locate_res))
				return $locate_res;

			foreach($where as $key=>$content) {
				// attempt to use each element of the content as possible location for the $id
				if($id == $key)
					return $content;

				if(is_array($content)) {
					$result = self::search_Object($content, $id);
					if(!is_null($result))
						return $result;
				}
			}
		} else
			return null;
	}
}


// The language searching method (non-oop, but VERY short)
function __($id, $precise = false)
{
	return MVC_NLS::get_Object($id, $precise);
}